package cn.kgc.rediscache.service.impl;

import cn.hutool.bloomfilter.BitMapBloomFilter;
import cn.hutool.bloomfilter.BloomFilterUtil;
import cn.kgc.rediscache.mapper.EmployeeMapper;
import cn.kgc.rediscache.pojo.Employee;
import cn.kgc.rediscache.service.EmployeeService;
import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.redisson.api.RBloomFilter;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Collections;
import java.util.Random;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;

//@CacheConfig(cacheNames = "emp")
@Service
public class EmployeeServiceImpl  implements EmployeeService {
    @Resource
    EmployeeMapper employeeMapper;
    @Resource
    StringRedisTemplate stringredisTemplate;
    @Resource
    RedissonClient redissonClient;


//    @Cacheable(condition = "#a0>1",sync = true)
    public Employee getEmp(Integer id) throws InterruptedException {
        Employee employee = null;
        String key = "emp::"+id;
        String lock = "emp::"+id+"lock";
        String empLockValue = UUID.randomUUID().toString();
        RBloomFilter<String> bloomFilter = redissonClient.getBloomFilter("phoneList");
        bloomFilter.tryInit(100000000L,0.03);
        if(!bloomFilter.contains(key)){
            System.out.println("执行了bloomFilter.contains(key)");
            return null;
        }
        String emplyeejson = stringredisTemplate.opsForValue().get(key);
//        if("empty".equals(emplyeejson)){
//            emplyeejson = null;
//        }


        if(emplyeejson==null){
            //使用nx分布式锁，避免缓存击穿

            Lock lock2 = redissonClient.getLock("lock");// 声明锁
            lock2.lock();//上锁
//            Boolean result = stringredisTemplate.opsForValue().setIfAbsent(lock, empLockValue, 1000, TimeUnit.SECONDS);
//            if(result){
            System.out.println("查询"+id+"号员工");
            employee = employeeMapper.getEmpById(id);
            if(employee!=null){
                String employeejson = JSON.toJSONString(employee);
                Random random = new Random();
                int i = random.nextInt(5)+1;
                stringredisTemplate.opsForValue().set(key,employeejson,i,TimeUnit.MINUTES);
            }else {
                stringredisTemplate.opsForValue().set(key,"empty",10, TimeUnit.SECONDS);
            }
//                stringredisTemplate.delete(lock);
//                使用LUA脚本删除锁
                //设置LUA脚本
//                String lua="if redis.call('get', KEYS[1])==ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end";
//                //脚本对象
//                DefaultRedisScript scriptObject=new DefaultRedisScript();
//                //设置返回值类型：报错，不支持Integer
//                scriptObject.setResultType(Long.class);
//
//                scriptObject.setScriptText(lua);
//                //执行脚本
//                stringredisTemplate.execute(scriptObject, Collections.singletonList(lock),empLockValue);
//
//            }else {
//                Thread.sleep(10000);
//                this.getEmp(id);
//            }
            lock2.unlock();// 解锁
        }else {
//            if(!"empty".equals(emplyeejson)){
                employee = JSON.parseObject(emplyeejson, Employee.class);
                return employee;
//            }
        }

        return employee;
    }

//    @CacheEvict(key = "#result.id")
    public Employee updateEmp(Employee employee){
        System.out.println("updateEmp:"+employee);
        employeeMapper.updateEmp(employee);
        return employee;
    }

//    @CacheEvict(key = "#id")
    public void deleteEmp(Integer id){
        System.out.println("deleteEmp:"+id);
        //employeeMapper.deleteEmpById(id);
    }


    public Employee getEmpByLastName(String lastName){
        return employeeMapper.getEmpByLastName(lastName);
    }



//    @CachePut(key = "#result.id")
    public Employee insertEmp(Employee employee){
        System.out.println("insertEmp:"+employee);
        employeeMapper.insertEmployee(employee);
        RBloomFilter<String> bloomFilter = redissonClient.getBloomFilter("phoneList");
        bloomFilter.tryInit(100000000L,0.03);
        bloomFilter.add("emp::"+employee.getId());
        return employee;
    }
}
